#ifndef QMAINCORE_H
#define QMAINCORE_H

#include <QDebug>
#include <QList>
#include <QRectF>
#include <QThread>
#include <QPicture>
#include <QPainter>

#include <algorithm>
#include <cmath>

#include "cell.h"

//! Cell calculator.
/*!
  QMainCore implements all calculations for the cell.
  Edges areas are calculated only once.
  Edges rigidities are calculated every rotational cycle.
  Rotational cycle is cell possibility to change it's active nodes
  by removing one of the frontal and adding adjucent to the new setof frontal nodes.
  Forces are calculated step by step: adhesion->polymerization->contraction->elastic for speed.
  */
class QMainCore : public QThread
{
    Q_OBJECT

private:
    bool stopped;  //!< While \c false thread is running.

    bool trackAdh; //!< Adhesion force is tracked for a vector field if true.
    bool trackPol; //!< Polymerization force is tracked for a vector field if true.
    bool trackCon; //!< Contraction force is tracked for a vector field if true.
    bool trackEla; //!< Elastic force is tracked for a vector field if true.

    CELL cell;     //!< Cell model.

    //Variables for internal usage
    bool unique;

    int id, id1, id2, id3, id4;

    double a, b, c;
    double alpha;
    double f, fx, fy;
    double fcon;
    double l;
    double q;
    double sum;
    double v;
    double xMax, xMin;

    QPointF A, B, C;
    QPointF bisectorCrossPoint;
    QPointF dir;
    QPointF N;
    QPointF O;
    QPointF p;
    QPointF tempCPos;
    QPointF testPoint;

protected:
    void findBoundaryElements(void);
    void calculateAreas(void);
    void calculateEdgesRigidity(void);
    void findCenterAndFrontCenterPoses(void);
    void calculateNodesPositions(void);

    void run(void);

public:
    explicit QMainCore(QObject *parent = 0);

    //! Convenience function. Calculates distance between two points.
    /*!
      \param p1 First point.
      \param p2 Second point.
      */
    static double distance(const QPointF &p1, const QPointF &p2 = QPointF(0,0));
    static double hillFunction(double sigma, double sigmaAV);

    //! Convenience function. Calculates cos(angle) between two vectors.
    /*!
      \param p1 First vector.
      \param p2 Second vector.
      */
    static double cosine(const QPointF &p1, const QPointF &p2);

signals:
    void cellChanged(const CELL &);
    void toggled(void);

public slots:  

    void stop(void);
    void reset(void);
    void resetDefaultLengths(void);
    void resetAdhesionPoses(void);

    //! Return id of the nearest to the pos node. If distance between pos and nearest node > 5, returns -1.
    int getNearestNode(const QPointF &pos) const;

    //! Return id of the nearest to the pos edge. If distance between pos and nearest node > 5, returns -1.
    int getNearestEdge(const QPointF &pos) const;

    //! Return id of the nearest to the pos area. If distance between pos and nearest node > 5, returns -1.
    int getNearestArea(const QPointF &pos) const;

    void addNode(const QPointF &pos);
    void addEdge(const QPointF &pos1, const QPointF &pos2);
    void addEdge(const int id1, const int id2);
    void addArea(const QRectF &rect);

    CELL getCell(void) const;
    void setCell(const CELL& _cell);

    void setModelPos(int id, const QPointF &pos);
    void setNodePos(int id, const QPointF &pos);
    void setAreaPos(int id, const QPointF &pos);

    void toggleNodeBoundary(const QPointF pos);
    void toggleNodeFrontal(const QPointF pos);

    void setTrackAdh(bool _trackAdh);
    void setTrackPol(bool _trackPol);
    void setTrackCon(bool _trackCon);
    void setTrackEla(bool _trackEla);
};

#endif // QMAINCORE_H
